; 2D to 3D image transform
; This script attempts to take a 2D pixel art image and
; create a 3D effect by adding a side, then the entire
; image receives a border. It works best on non-bordered
; images with no empty spaces in the middle.

(define (script-fu-2Dimage-3Dimage            ; Main function, declaring variables from register function
        img            ; Current image
        layerNormal    ; Current layer (should only be one)
        imgScale       ; Factor to scale by
        imgThickness   ; Thickness of 3D side
        imgLightEdge   ; Thickness of light edge
        imgBorder      ; Thickness of border
        imgFeather     ; Border feather radius
        borderColor    ; Color of the border
        grainOpacity)  ; Opacity of the grain merge gradient

  (let* (
        (imgWidth (car (gimp-image-width img)))    ; Returns current image width and sets variable
        (imgHeight (car (gimp-image-height img)))  ; Returns current image height and sets variable
        (newWidth (+ (* imgWidth imgScale) imgThickness (* imgBorder 2)))  ; New width with scale, borders and thickness
        (newHeight (+ (* imgHeight imgScale) (* imgBorder 2)))  ; New height with scale and borders
        (layerLight 0)        ; Creates a layer variable for later
        (layerDark 0)         ; Creates a layer variable for later
        (layerFlat 0)         ; Creates a layer variable for later
        (layerBorder 0)       ; Creates a layer variable for later
        (layerDone 0)         ; Creates a layer variable for later
        )

        (gimp-image-undo-group-start img)   ; Starts lumping the following actions into one undo

        (gimp-image-scale-full      ; Scales the image
             img                            ; This image
             (* imgWidth imgScale)          ; New image width (image width * scale factor)
             (* imgHeight imgScale)         ; New image height (image height * scale factor)
             0)                             ; Interpolation: none

        (gimp-image-resize        ; Resizes the canvas to account for 3D side and borders
             img                       ; This image
             newWidth                  ; Extends width for thickness and borders on both sides
             newHeight                 ; Extends height for borders on both sides
             imgBorder                 ; Offsets image one border thickness from left side
             imgBorder)                ; Offsets image one border thickness from top

        (gimp-layer-resize-to-image-size layerNormal)    ; Fits layer to image after canvas resize

        (set! layerLight (car (gimp-layer-copy layerNormal TRUE)))     ; Copies the original layer, returns it
        (gimp-image-add-layer           ; Adding the newly copied layer to the layer stack
             img                        ; This image
             layerLight                 ; Layer name
             1)                         ; Makes this the second layer

        (set! layerDark (car (gimp-layer-copy layerNormal TRUE)))      ; Copies original layer, returns it
        (gimp-image-add-layer           ; Adding the newly copied layer to the layer stack
             img                        ; This image
             layerDark                  ; Layer name
             2)                         ; Makes this the third layer

        (gimp-drawable-offset      ; Moves the selected layer over
             layerDark             ; Moving the dark layer over
             FALSE                 ; Fills vacated regions
             1                     ; Fills vacated regions with transparency
             imgThickness          ; Moves layer to the right by amount of thickness
             0)                    ; Doesn't move layer in the y direction

        (gimp-drawable-offset      ; Moves the selected layer over
             layerLight            ; Moving the light layer over
             FALSE                 ; Fills vacated regions
             1                     ; Fills vacated regions with transparency
             imgLightEdge          ; Moves layer to the right by light edge thickness
             0)                    ; Doesn't move layer in the y direction

        (gimp-brightness-contrast  ; Sets brightness/darkness of a layer
             layerDark             ; Using the dark layer
             -96                   ; Darkens image
             0)                    ; Not changing the contrast

        (gimp-brightness-contrast  ; Sets brightness/darkness of a layer
             layerLight            ; Using the light layer
             127                   ; Brightens image
             0)                    ; Not changing the contrast

        (gimp-context-set-foreground '(0 0 0))         ; Set foreground color to black
        (gimp-context-set-background '(255 255 255))   ; Set background color to white
        (gimp-selection-layer-alpha layerNormal)       ; Alpha to selection for the original layer
        (gimp-edit-blend        ; Fills selection with the gradient
             layerNormal             ; Selects the original layer
             0                       ; Type of blend: foreground to background
             21                       ; Paint-mode: grain merge
             0                       ; Gradient type: linear
             grainOpacity            ; Opacity
             0                       ; Offset: none
             0                       ; Repeat mode: none
             FALSE                   ; Reverse mode: nope
             FALSE                   ; Don't do adaptive supersampling
             1                       ; No recursion
             0                       ; No supersampling threshold
             TRUE                    ; Use dithering to reduce banding
             1                       ; Starting x coordinate
             1                       ; Starting y coordinate
             newWidth                ; Ending x coordinate (60% of image width)
             1)                      ; Ending y coordinate

        (set! layerFlat (car(gimp-image-merge-visible-layers img 0)))  ; Merges all visible layers, returns new layer
        (gimp-selection-layer-alpha layerFlat)          ; Alpha to selection for flat layer
        (gimp-selection-grow img imgBorder)             ; Grows selection by border thickness
        (gimp-selection-feather img imgFeather)                  ; Feathers selection with user input radius

        (set! layerBorder (car (gimp-layer-new          ; Creates new layer for the border
             img                  ; This image
            newWidth             ; Set width to width of image
             newHeight            ; Set height to height of image
             1                    ; Type of image: RGBA
             "Border layer"       ; Layer name
             100                  ; Opacity: 100
             0)))                 ; Normal mode
        (gimp-image-add-layer       ; Adding border layer to stack
             img                        ; This image
             layerBorder                ; Layer name
             1)                         ; Adds border layer on the bottom
        (gimp-context-set-foreground borderColor)       ; Sets the foreground to border color
        (gimp-edit-fill layerBorder 0)                  ; Fills selection on border layer with foreground
        (set! layerDone (car(gimp-image-merge-visible-layers img 0)))  ; Merges all visible layers, returns new layer
        (gimp-selection-none img)       ; Removes selection from image

        (gimp-image-undo-group-end img)   ; End of actions lumped into one undo
        (gimp-displays-flush)             ; Refreshes the display so all the changes can be seen
  )
)

(script-fu-register
  "script-fu-2Dimage-3Dimage"
  "2D to 3D..."
  "Takes a pixel art image and creates a 3D effect."
  "najzere & Procyon @ strategywiki.org"
  "GFDL"
  "March 6, 2008"
  "RGBA"
  SF-IMAGE       "Image"            0
  SF-DRAWABLE    "Drawable"         0
  SF-ADJUSTMENT  "Scale"            '(1 0 100 1 5 1 1)
  SF-ADJUSTMENT  "3D thickness"     '(15 1 100 1 5 0 1)
  SF-ADJUSTMENT  "Light edge"       '(2 1 100 1 1 0 1)
  SF-ADJUSTMENT  "Border size"      '(2 0 50 1 1 0 1)
  SF-ADJUSTMENT  "Border feather"   '(2 0 50 1 1 0 1)
  SF-COLOR       "Border color"     '(0 0 0)
  SF-ADJUSTMENT  "Gradient opacity" '(50 0 100 .1 1 1 0)
)

(script-fu-menu-register "script-fu-2Dimage-3Dimage"
                         "<Image>/Image/Transform")